#include <stdio.h>
#include <stdbool.h>
#ifndef NONUSE_GLIB
#include <glib-object.h>
#include <glib/gprintf.h>

gboolean object_set_value(GObject *obj,
    const gchar *name, gpointer value)
{
  GObjectClass *obj_class = NULL;
  GParamSpec *pspec = NULL;

  obj_class = G_OBJECT_GET_CLASS(obj);
  pspec = g_object_class_find_property(obj_class, name);
  if (pspec) {
    if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_STRING) {
      char *str = value;
      g_object_set(obj, name, str, NULL);
    } else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_INT) {
      gint int32 = *(gint *)value;
      g_object_set(obj, name, int32, NULL);
    } else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_BOOLEAN) {
      gboolean bn = *(gboolean *)value;
      g_object_set(obj, name, bn, NULL);
    } else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_INT64) {
      gint64 int64 = *(gint64 *)value;
      g_object_set(obj, name, int64, NULL);
    } else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_FLOAT) {
      gfloat f = *(gfloat *)value;
      g_object_set(obj, name, f, NULL);
    } else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_POINTER) {
      g_object_set(obj, name, value, NULL);
    }
  }
  return false;
}
void objects_set_value(void *obj, const char *name, void *value)
{
  gpointer next;

  while (obj) {
    g_object_get(obj, "next", &next, NULL);
    object_set_value(obj, name, value);
    obj = next;
  }
}
void object_deep_set(void *obj, const char *name, void *value)
{
  gpointer next, son;

  object_set_value(obj, name, value);
  g_object_get(obj, "son", &son, NULL);
  while (son) {
    g_object_get(son, "next", &next, NULL);
    object_deep_set(son, name, value);
    son = next;
  }
}
void print_value(const GValue *value)
{
  if (G_VALUE_HOLDS_STRING(value)) {
    printf("%s", g_value_get_string(value));
  } else if (G_VALUE_HOLDS_INT64(value)) {
    printf("%"G_GINT64_FORMAT, g_value_get_int64(value));
  } else if (G_VALUE_HOLDS_INT(value)) {
    printf("%d", g_value_get_int(value));
  } else if (G_VALUE_HOLDS_UINT(value)) {
    printf("%u", g_value_get_uint(value));
  } else if (G_VALUE_HOLDS_LONG(value)) {
    printf("%ld", g_value_get_long(value));
  } else if (G_VALUE_HOLDS_ULONG(value)) {
    printf("%lu", g_value_get_ulong(value));
  } else if (G_VALUE_HOLDS_FLOAT(value)) {
    printf("%f", g_value_get_float(value));
  } else if (G_VALUE_HOLDS_DOUBLE(value)) {
    printf("%f", g_value_get_double(value));
  } else if (G_VALUE_HOLDS_BOOLEAN(value)) {
    printf("%s", g_value_get_boolean(value) ? "TRUE" : "FALSE");
  } else if (G_VALUE_HOLDS_POINTER(value)) {
    printf("%p", g_value_get_pointer(value));
  } else {
    printf("Unknown type");
  }
}

int object_print(void *obj)
{
  GObject *object = obj;
  GObjectClass *obj_class = G_OBJECT_GET_CLASS(object);
  GParamSpec **properties;
  guint n_properties, i;

  properties = g_object_class_list_properties(
      obj_class, &n_properties);

  for (i = 0; i < n_properties; i++) {
    GParamSpec *pspec = properties[i];
    GValue value = G_VALUE_INIT;

    g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec));
    g_object_get_property(object,
        g_param_spec_get_name(pspec), &value);

    g_print("Property: %s\t", g_param_spec_get_name(pspec));
    g_print("Type: %s\t", g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec)));
    g_print("Value: ");
    print_value(&value);
    printf("\t");
    if (G_VALUE_HOLDS_POINTER(&value) && g_value_get_pointer(&value)) {
      if (strcmp("parent", g_param_spec_get_name(pspec))) {
        printf("\n");
      //if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_OBJECT) {
        if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_POINTER) {
          object_print(g_value_get_pointer(&value));
      //    printf("son\n");
        }
      }
    }

    g_value_unset(&value);
  }

  g_free(properties);
  return true;
}
int object_print_delim(void *obj, int delim)
{
  GObject *object = obj;
  GObjectClass *obj_class = G_OBJECT_GET_CLASS(object);
  GParamSpec **properties;
  guint n_properties, i;

  properties = g_object_class_list_properties(obj_class, &n_properties);

  for (i = 0; i < n_properties; i++) {
    GParamSpec *pspec = properties[i];
    //if (strcmp("thread", g_param_spec_get_name(pspec)) && strcmp("parent", g_param_spec_get_name(pspec))) {
    if (strcmp("parent", g_param_spec_get_name(pspec))) {
      GValue value = G_VALUE_INIT;

      g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec));
      g_object_get_property(object,
          g_param_spec_get_name(pspec), &value);
      if (G_PARAM_SPEC_VALUE_TYPE(pspec) != G_TYPE_POINTER) {
        g_printf("[%s]", g_param_spec_get_name(pspec));
        //printf("Type: %s\t", g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec)));
        //printf("Value: ");
        print_value(&value);
        printf("\t");
      }
      if (G_VALUE_HOLDS_POINTER(&value) && g_value_get_pointer(&value)) {
      //if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_OBJECT) {
        if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_POINTER) {
          //g_printf("|");
          if (!strcmp("son", g_param_spec_get_name(pspec))) {
            printf("\n");
            int j;
            g_printf("|");
            for (j = 0; j < delim+1; j++) {
              g_printf("-- ");
            }
            object_print_delim(g_value_get_pointer(&value), delim+1);
          } else if (!strcmp("next", g_param_spec_get_name(pspec))) {
            printf("\n");
            int j;
            g_printf("|");
            for (j = 0; j < delim; j++) {
              g_printf("-- ");
            }
            object_print_delim(g_value_get_pointer(&value), delim);
          } else {
        g_printf("[%s]", g_param_spec_get_name(pspec));
        //printf("Type: %s\t", g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec)));
        //printf("Value: ");
        print_value(&value);
        printf("\t");
          }
      //    printf("son\n");
        }
      }
      g_value_unset(&value);
    }
  }
  if (!delim)
    printf("\n");

  g_free(properties);
  return true;
}

void *object_add_end(void *start, void *end)
{
  GObject *next = NULL, *now = start;

  if (start == end) {
    g_warning("start is end");
    exit(1);
  }
  if (!start) {
    return end;
  }
  g_object_get(now, "next", &next, NULL);
  while (next) {
    now = next;
    g_object_get(now, "next", &next, NULL);
  }
  g_object_set(now, "next", end, NULL);
  return start;
}
gboolean object_is_key_value(GObject *obj,
    const gchar *name, gpointer value)
{
  GObjectClass *obj_class = NULL;
  GParamSpec *pspec = NULL;

  obj_class = G_OBJECT_GET_CLASS(obj);
  pspec = g_object_class_find_property(obj_class, name);
  if (pspec) {
    if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_STRING) {
      char *str = NULL;
      g_object_get(obj, name, &str, NULL);
      if (str) {
        if (!strcmp(str, value)) {
          free(str);
          return true;
        }
        free(str);
      } else {
 //       g_warning("F-%s L%d f-%s %s:str is NULL", __FILE__, __LINE__, __func__,
  //          name);
      }
    } else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_INT) {
      gint int32;
      g_object_get(obj, name, &int32, NULL);
      if (int32 == *(gint *)value) {
        return true;
      }
    } else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_BOOLEAN) {
      gboolean bn;
      g_object_get(obj, name, &bn, NULL);
      if (bn == *(gboolean *)value) {
        return true;
      }
    } else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_INT64) {
      gint64 int64;
      g_object_get(obj, name, &int64, NULL);
      if (int64 == *(gint64 *)value) {
        return true;
      }
    } else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_FLOAT) {
      gfloat f;
      g_object_get(obj, name, &f, NULL);
      if (f == *(gfloat *)value) {
        return true;
      }
    }
  }
  return false;
}
void *objects_get_object(void *obj, const char *name, void *value)
{
  GObject *next;

  while (obj) {
    g_object_get(obj, "next", &next, NULL);
    if (object_is_key_value(obj, name, value)) {
      return obj;
    }
    obj = next;
  }
  return obj;
}
void *object_from_keys_value(void *obj,
    const char *name1, void *value1,
    const char *name2, void *value2)
{
  GObject *next;

  while (obj) {
    g_object_get(obj, "next", &next, NULL);
    if (object_is_key_value(obj, name1, value1) && \
        object_is_key_value(obj, name2, value2)) {
      return obj;
    }
    obj = next;
  }
  return obj;
}
bool object_is_collector(void *obj)
{
  gint type = 0;

  g_object_get(obj, "type", &type, NULL);
  if (type < 2)
    return true;
  else
    return false;
}
bool object_is_push(void *obj)
{
  gint type = 0;

  g_object_get(obj, "type", &type, NULL);
  if ((type == 4) || (type == 5))
    return true;
  else
    return false;
}
bool object_is_controled(void *obj)
{
  gint type = 0;

  g_object_get(obj, "type", &type, NULL);
  if (type < 2)
    return true;
  else
    return false;
}

int object_get_brother_num(void *obj)
{
  GObject *object = obj, *next;
  int rc = 0;

  while (object) {
    g_object_get(object, "next", &next, NULL);
    rc++;
    object = next;
  }
  return rc;
}
int object_get_son_num(void *obj)
{
  GObject *object = obj, *son;
  int rc = 0;

  g_object_get(object, "son", &son, NULL);
  rc = object_get_brother_num(son);
  return rc;
}
int object_get_grandson_num(void *obj)
{
  GObject *object = obj, *son, *next_son;
  int rc = 0;

  g_object_get(object, "son", &son, NULL);
  while (son) {
    g_object_get(son, "next", &next_son, NULL);
    rc += object_get_son_num(son);
    son = next_son; 
  }
  return rc;
}
#else
#define T_OBJECT_PROP_MAX 255
enum t_object_prop_type {
  TINT,
  TPOINTER,
};
struct t_object {
  int type;
  int prop_num;
  char *prop_names[T_OBJECT_PROP_MAX];
  int prop_types[T_OBJECT_PROP_MAX];
  int prop_int_values[T_OBJECT_PROP_MAX];
  void *prop_pointer_values[T_OBJECT_PROP_MAX];
};
void t_object_new(int type)
{
  struct t_object *self = calloc(1, sizeof(*self));

  self->type = type;
  if (type)
}
void t_object_set(void *obj, ...)
{
  if (obj == NULL) return;

  va_list args;
  va_start(args, obj);  // 初始化不定参数列表

  while (1) {
    const char *property_name = va_arg(args, const char *);
    if (property_name == NULL) break;  // 遇到 NULL 时结束

    if (strcmp(property_name, "my_property1") == 0) {
        int *value = va_arg(args, int *);
        *value = obj->my_property1;
    } else if (strcmp(property_name, "my_property2") == 0) {
        float *value = va_arg(args, float *);
        *value = obj->my_property2;
    } else if (strcmp(property_name, "my_property3") == 0) {
        char *value = va_arg(args, char *);
        strncpy(value, obj->my_property3, 50);
    }
  }

  va_end(args);  // 清理不定参数列表
}
void t_object_get(void *obj, ...)
{
  if (obj == NULL) return;

  va_list args;
  va_start(args, obj);  // 初始化不定参数列表

  while (1) {
    const char *property_name = va_arg(args, const char *);
    if (property_name == NULL) break;  // 遇到 NULL 时结束

    if (strcmp(property_name, "my_property1") == 0) {
        int *value = va_arg(args, int *);
        *value = obj->my_property1;
    } else if (strcmp(property_name, "my_property2") == 0) {
        float *value = va_arg(args, float *);
        *value = obj->my_property2;
    } else if (strcmp(property_name, "my_property3") == 0) {
        char *value = va_arg(args, char *);
        strncpy(value, obj->my_property3, 50);
    }
  }

  va_end(args);  // 清理不定参数列表
}
#endif
